package com.gzs.learn.springcloud.config;

import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotationUtils;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.gzs.learn.springcloud.common.BeanUtil;
import com.gzs.learn.springcloud.common.JsonUtil;
import com.gzs.learn.springcloud.config.hotconfig.HotCofnigListener;
import com.gzs.learn.springcloud.config.hotconfig.HotConfig;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Configuration
@ConditionalOnProperty(prefix = "spring.cloud.nacos.config", name = "enabled", havingValue = "true")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@Slf4j
public class HotConfigConfiguration implements InitializingBean, ApplicationContextAware {
    @Value("${spring.application.name}")
    private String defaultGroup;

    @Value("${spring.cloud.nacos.config.timeout}")
    private int timeOut;

    private ApplicationContext ctx;

    private final NacosConfigManager nacosConfigManager;

    @Override
    public void afterPropertiesSet() throws Exception {
        ConfigService configService = nacosConfigManager.getConfigService();
        Map<String, Object> beanMap = ctx.getBeansWithAnnotation(HotConfig.class);
        for (Map.Entry<String, Object> entry : beanMap.entrySet()) {
            Object obj = entry.getValue();
            if (obj == null) {
                log.warn("request object instnce [{}],but found null", entry.getKey());
                continue;
            }
            HotConfig hotConfig = AnnotationUtils.findAnnotation(obj.getClass(), HotConfig.class);
            if (!hotConfig.enable()) {
                continue;
            }
            String dataId = hotConfig.dataId();
            String group = hotConfig.group();
            group = StringUtils.isBlank(group) ? defaultGroup : group;
            Class<?> type = hotConfig.type();
            String clz = type.getName();

            // init config from remote nacos server
            String configInfo = configService.getConfig(dataId, group, timeOut);
            BeanUtil.copyProperties(JsonUtil.parseObject(configInfo, type), obj);
            // add listener
            Listener listener = new HotCofnigListener(obj, type);

            configService.addListener(dataId, group, listener);
            log.info("register hot config dataId [{}],group [{}],class [{}] success", dataId, group, clz);
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.ctx = applicationContext;
    }
}
